package com.zjhcsoft.common.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.springframework.jdbc.UncategorizedSQLException;

import com.zjhcsoft.common.object.EqualObj;
import com.zjhcsoft.common.object.GridObj;
import com.zjhcsoft.common.object.OrderObj;
import com.zjhcsoft.common.object.PageObj;
import com.zjhcsoft.util.CommonUtil;



/**
 * DAO操作公共类
 * 
 * @author 
 * @date 2011-11-8
 * @time 下午01:50:11
 * @version 1.0
 * @updater
 * @update-time
 * @update-info
 * @param <T>
 * @param <ID>
 */
@SuppressWarnings("unchecked")
public abstract class MybatisCommonDao<T, ID extends Serializable> extends
		MybatisBaseDao {
	private static final Logger logger = Logger.getLogger(MybatisCommonDao.class);
	//private static final Log logger = LogFactory.getLog(MybatisCommonDao.class);
	protected String tableName;
	protected String primaryKeyName;
	protected String defaultSort;
	protected String defaultDir;
	protected String flagName = "flag";// 删除标志的名称：默认flag

	public String getFlagName() {
		return flagName;
	}

	public void setFlagName(String flagName) {
		this.flagName = flagName;
	}

	public String getPrimaryKeyName() {
		return primaryKeyName;
	}

	public void setPrimaryKeyName(String primaryKeyName) {
		this.primaryKeyName = primaryKeyName;
	}

	public String getTableName() {
		return tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	public String getDefaultSort() {
		return defaultSort;
	}

	public void setDefaultSort(String defaultSort) {
		this.defaultSort = defaultSort;
	}

	public String getDefaultDir() {
		return defaultDir;
	}

	public void setDefaultDir(String defaultDir) {
		this.defaultDir = defaultDir;
	}

	/**
	 * 对象转化为相等的list对象
	 * 
	 * @param from_entity
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	private List<EqualObj> getEqualList(T entity)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		List<EqualObj> result = null;
		if (entity != null) {
			result = new ArrayList<EqualObj>();
			Set<Entry<String, Object>> newSet = PropertyUtils.describe(entity)
					.entrySet();
			for (Entry<String, Object> newEntry : newSet) {
				Object key = newEntry.getKey();
				Object value = newEntry.getValue();
				if (key == null || key.equals("class")) {
					continue;
				}
				if (key.equals(this.flagName) && value == null) {// 如里面有flag标志，默认去flag等于0的记录
					value = new Integer(0);
				}
				if (value == null) {
					continue;
				}
				EqualObj eo = new EqualObj(key.toString(), "'"
						+ changeFormate(value) + "'");
				result.add(eo);
			}
		}
		return result;
	}

	protected String changeFormate(Object value) {
		String returnObj = "";
		if (value instanceof Date) {
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			returnObj = dateFormat.format(value);
		} else {
			returnObj = value.toString();
		}
		return returnObj;
	}

	/**
	 * 通过对象取得对象的主键值
	 * 
	 * @param entity
	 * @return
	 * @throws Exception 
	 * @throws ParamException
	 * @throws DaoException
	 */
	private ID getPrimaryKey(T entity) throws Exception {
		if (CommonUtil.isEmpty(primaryKeyName)) {
			throw new Exception("getPrimaryKey：主键不能为空！");
			
		}
		Object primaryKeyValueObj = getPropertyValue(entity, primaryKeyName);
		return (ID) primaryKeyValueObj;
	}

	/**
	 * 取得对象的属性值
	 * 
	 * @param entity
	 * @param propertyName
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	private Object getPropertyValue(T entity, String propertyName)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		return PropertyUtils.getProperty(entity, propertyName);
	}

	/**
	 * 设置对象的属性值
	 * 
	 * @param entity
	 * @param propertyName
	 * @param PropertyValue
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	private void setPropertyValue(T entity, String propertyName,
			Object PropertyValue) throws IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		PropertyUtils.setProperty(entity, propertyName, PropertyValue);
	}

	/**
	 * 从map中取得对象实例
	 * 
	 * @param entityClass
	 * @param result
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws InstantiationException
	 */
	private T getInstanceFromMap(Class<T> entityClass,
			Map<String, Object> result) throws IllegalAccessException,
			InvocationTargetException, NoSuchMethodException,
			InstantiationException {
		T entity = entityClass.newInstance();
		for (Iterator<Entry<String, Object>> it = result.entrySet().iterator(); it
				.hasNext();) {
			Entry<String, Object> o = it.next();
			String key = o.getKey();
			Object value_obj = o.getValue();
			if (key != null && value_obj != null) {
				//key = key.toLowerCase();
				Class<?> vo_class = PropertyUtils.getPropertyType(entity, key);
				if (vo_class == null) {
					logger.debug("字段" + key + "在java类中没有找到");
					continue;
				}
				if (vo_class.isInstance(value_obj)) {
					setPropertyValue(entity, key, value_obj);
				} else {
					logger.debug("字段" + key + "对应存在问题:数据库中类型："
							+ value_obj.getClass().getSimpleName()
							+ ",java中类型：" + vo_class.getSimpleName());
					if (value_obj instanceof BigInteger) {
						BigInteger value_biginteger = (BigInteger) value_obj;
						if (vo_class.isAssignableFrom(Integer.class)) {
							setPropertyValue(entity, key, value_biginteger
									.intValue());
						} else if (vo_class.isAssignableFrom(Long.class)) {
							setPropertyValue(entity, key, value_biginteger
									.longValue());
						} else if (vo_class.isAssignableFrom(Float.class)) {
							setPropertyValue(entity, key, value_biginteger
									.floatValue());
						} else if (vo_class.isAssignableFrom(String.class)) {
							setPropertyValue(entity, key, value_biginteger
									.toString());
						}
					} else if (value_obj instanceof BigDecimal) {
						BigDecimal value_bigdecimal = (BigDecimal) value_obj;
						if (vo_class.isAssignableFrom(Integer.class)) {
							setPropertyValue(entity, key, value_bigdecimal
									.intValue());
						} else if (vo_class.isAssignableFrom(Long.class)) {
							setPropertyValue(entity, key, value_bigdecimal
									.longValue());
						} else if (vo_class.isAssignableFrom(Float.class)) {
							setPropertyValue(entity, key, value_bigdecimal
									.floatValue());
						} else if (vo_class.isAssignableFrom(String.class)) {
							setPropertyValue(entity, key, value_bigdecimal
									.toString());
						}
					} else if (value_obj instanceof Integer) {
						Integer value_int = (Integer) value_obj;
						if (vo_class.isAssignableFrom(Integer.class)) {
							setPropertyValue(entity, key, value_int.intValue());
						} else if (vo_class.isAssignableFrom(Long.class)) {
							setPropertyValue(entity, key, value_int.longValue());
						} else if (vo_class.isAssignableFrom(Float.class)) {
							setPropertyValue(entity, key, value_int
									.floatValue());
						} else if (vo_class.isAssignableFrom(String.class)) {
							setPropertyValue(entity, key, value_int.toString());
						}
					}
				}
			}
		}
		return entity;
	}

	/**
	 * 从list<map>中取得对象实例list
	 * 
	 * @param entityClass
	 * @param mapList
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws InstantiationException
	 */
	private List<T> getListInstanceFromListMap(Class<T> entityClass,
			List<Map<String, Object>> mapList) throws IllegalAccessException,
			InvocationTargetException, NoSuchMethodException,
			InstantiationException {
		List<T> resultList = null;
		if (mapList != null) {
			resultList = new ArrayList<T>();
			for (Map<String, Object> map : mapList) {
				T entity = this.getInstanceFromMap(entityClass, map);
				resultList.add(entity);
			}
		}
		return resultList;
	}

	/**
	 * 根据例子来查找列表
	 * 
	 * @param entity
	 * @return
	 * @throws BaseException
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws SQLException
	 */
	private List<T> findByExample(T entity, PageObj page, OrderObj order)
			throws Exception, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException,
			InstantiationException, SQLException {
		if (CommonUtil.isEmpty(tableName)) {
			throw new Exception("findByExample：tableName不能为空");
		}
		HashMap<String, Object> params = new HashMap<String, Object>();
		params.put("tableName", tableName);
		List<EqualObj> conditionList = getEqualList(entity);
		params.put("conditionList", conditionList);
		if (order == null) {
			if (!CommonUtil.isEmpty(defaultSort)) {
				order = new OrderObj(defaultSort, defaultDir);
			}
		}
		if (order != null) {
			params.putAll(order.toMap());
		}
		if (page != null) {
			params.putAll(page.toMap());
		}
		List<Map<String, Object>> list = this.queryForMapObjectList(
				"IbatisCommonDao_findByExample", params);
		Class<T> entityClass = (Class<T>) entity.getClass();
		return this.getListInstanceFromListMap(entityClass, list);
	}

	/**
	 * 加载对象
	 * 
	 * @param entity
	 * @return
	 * @throws Exception
	 */
	public T load(Class<T> entityClass, ID id) throws Exception {
		if (CommonUtil.isEmpty(entityClass)) {
			throw new Exception("load：实体类不能空");
		}
		if (id == null) {
			throw new Exception("load：id不能为空");
		}
		if (CommonUtil.isEmpty(primaryKeyName)) {
			throw new Exception("load：primaryKeyName为空");
		}
		List<T> list = this.findByProperty(entityClass, primaryKeyName, id);
		if (list == null || list.size() == 0) {
			throw new  Exception("load：加载时数据库中不存在记录");
		} else if (list.size() > 1) {
			throw new Exception("load：加载时数据库中存在1条记录以上记录");
		}
		return list.get(0);
		
	}

	/**
	 * 加载对象,若找不到或者记录过多的时候会报错
	 * 
	 * @param entity
	 * @return
	 * @throws BaseException
	 */
	public T load(T entity) throws Exception {
		Class<T> entityClass = (Class<T>) entity.getClass();
		ID id = getPrimaryKey(entity);
		return load(entityClass, id);
	}

	/**
	 * 加载属性相同对象
	 * 
	 * @param entity
	 * @return
	 * @throws BaseException
	 */
	public T loadEqual(T entity) throws Exception {
		try {
			if (entity == null) {
				throw new Exception("loadEqual：entity不能为空");
			}
			List<T> list = this.findByExample(entity);
			if (list == null || list.size() == 0) {
				throw new Exception("loadEqual：加载时数据库中不存在记录");
			} else if (list.size() > 1) {
				throw new Exception("loadEqual：加载时数据库中存在1条记录以上记录");
			}
			return list.get(0);
		} catch (UncategorizedSQLException e1) {
			throw new Exception("loadEqual：加载出错");
		} 
	}

	/**
	 * 查找一条记录，若找不到则返回null，不会报错
	 * 
	 * @param entityClass
	 * @param id
	 * @return
	 * @throws BaseException
	 */
	public T findById(Class<T> entityClass, ID id) throws Exception {
		T entity = null;
		if (CommonUtil.isEmpty(entityClass)) {
			throw new Exception("findById：entityClass不能为空");
		}
		if (id == null) {
			throw new Exception("id为空");
		}
		if (CommonUtil.isEmpty(primaryKeyName)) {
			throw new Exception("findById：primaryKeyName不能为空");
		}
		List<T> list = this.findByProperty(entityClass, primaryKeyName, id);
		if (list != null && list.size() > 0) {
			if (list.size() > 1) {
				throw new Exception("findById：查找相同记录时数据库中存在1条记录以上记录");
			} else {// 只有一条记录的情况
				entity = list.get(0);
			}
		}
		return entity;
		
	}

	/**
	 * 根据例子来查找列表
	 * 
	 * @param entity
	 * @return
	 * @throws BaseException
	 */
	public List<T> findByExample(T entity) throws Exception {
		return findByExample(entity, null, null);
		
	}

	/**
	 * 根据属性来查找对象
	 * 
	 * @param entityClass
	 * @param propertyName
	 * @param propertyValue
	 * @return
	 * @throws BaseException
	 */
	public List<T> findByProperty(Class<T> entityClass, String propertyName,
			Object propertyValue) throws Exception {
		if (entityClass == null) {
			throw new Exception("findByProperty：entityClass不能为空");
		}
		if (CommonUtil.isEmpty(propertyName)) {
			throw new Exception("findByProperty：propertyName不能为空");
		}
		if (propertyValue == null) {
			throw new Exception("findByProperty：propertyValue不能为空");
		}
		T entity = entityClass.newInstance();
		this.setPropertyValue(entity, propertyName, propertyValue);
		return this.findByExample(entity);
		
	}

	/**
	 * 分页查询记录
	 * 
	 * @param entity
	 * @param page
	 * @param order
	 * @return
	 * @throws BaseException
	 */
	public GridObj findByPage(T entity, PageObj page, OrderObj order)
			throws Exception {
		if (entity == null) {
			throw new Exception("findByPage：entity不能为空");
		}
		if (page == null) {
			page = new PageObj();
		}

		List<T> root = findByExample(entity, page, order);
		Long count = countEqual(entity);
		return new GridObj(root, count);
		
	}
	
	/**
	 * 分页查询记录(不加条件)
	 * 
	 * @param entity
	 * @param page
	 * @param order
	 * @return
	 * @throws BaseException
	 */
	public GridObj findByPage(Class<T> entityClass, PageObj page, OrderObj order)
			throws Exception {
		T entity = entityClass.newInstance();
		return findByPage(entity, page, order);
		
	}

	/**
	 * 查找全部
	 * 
	 * @return
	 * @throws BaseException
	 */
	public List<T> findAll(Class<T> entityClass) throws Exception {
		T entity = entityClass.newInstance();
		return findByExample(entity);
		
	}

	/**
	 * 通用的插入操作
	 * 
	 * @param entity
	 * @return
	 * @throws BaseException
	 */
	public ID insert(T entity) throws Exception {
		if (CommonUtil.isEmpty(tableName)) {
			throw new Exception("insert：tableName不能为空");
		}
		if (CommonUtil.isEmpty(primaryKeyName)) {
			throw new  Exception("insert：primaryKeyName不能为空");
		}
		HashMap<String, Object> params = new HashMap<String, Object>();
		params.put("tableName", tableName);
		List<EqualObj> conditionList = getEqualList(entity);
		params.put("conditionList", conditionList);
		ID id = (ID) this.executeInsert("IbatisCommonDao_insert", params);
		ID oldId = this.getPrimaryKey(entity);
		if (oldId == null) {
			setPropertyValue(entity, primaryKeyName, null);
		} else {
			id = oldId;
		}
		return id;
	}

	/**
	 * 通用更新操作,注意此操作会将对象中属性为空字段更新到数据库中（目前暂时未实现）
	 * 
	 * @param entity
	 * @throws BaseException
	 */
	public boolean update(T entity) throws Exception {
		boolean flag = true;
		
		if (CommonUtil.isEmpty(tableName)) {
			throw new Exception("update：tableName不能为空");
		}
		if (CommonUtil.isEmpty(primaryKeyName)) {
			throw new Exception("update：primaryKeyName不能为空");
		}
		HashMap<String, Object> params = new HashMap<String, Object>();
		params.put("tableName", tableName);
		List<EqualObj> conditionList = getEqualList(entity);
		params.put("conditionList", conditionList);
		params.put("primaryKeyName", primaryKeyName);
		Object primaryKeyValueObj = getPropertyValue(entity, primaryKeyName);
		params.put("primaryKeyValue", primaryKeyValueObj);
		this.executeUpdate("IbatisCommonDao_update", params);
		 
		return flag;
	}

	/**
	 * 仅更新非空的部分
	 * 
	 * @param entity
	 * @throws BaseException
	 */
	public boolean updateIgnoreNull(T entity) throws Exception {
		boolean flag = true;
		try {
			flag = this.update(entity);
		} catch (Exception e) {
			flag = false;
			throw new Exception(e);
		}
		return flag;
	}

	/**
	 * 通用删除
	 * 
	 * @param entityClass
	 * @param id
	 * @throws BaseException
	 */
	public boolean delete(Class<T> entityClass, ID id) throws Exception {
		boolean flag = true;
		try {
			if (CommonUtil.isEmpty(entityClass)) {
				throw new Exception("delete：entityClass不能为空");
			}
			if (CommonUtil.isEmpty(id)) {
				throw new Exception("delete：id不能为空");
			}
			if (CommonUtil.isEmpty(tableName)) {
				throw new Exception("delete：tableName不能为空");
			}
			if (CommonUtil.isEmpty(primaryKeyName)) {
				throw new Exception("delete：primaryKeyName不能为空");
			}
			HashMap<String, Object> params = new HashMap<String, Object>();
			params.put("tableName", tableName);
			params.put("primaryKeyName", primaryKeyName);
			params.put("primaryKeyValue", id);
			this.executeDelete("IbatisCommonDao_delete", params);
		} catch (Exception e) {
			flag = false;
			throw new Exception(e);
		}
		return flag;
	}

	/**
	 * 通用删除
	 * 
	 * @param entityClass
	 * @param id
	 * @throws BaseException
	 */
	public boolean delete(T entity) throws Exception {
		boolean flag = true;
		try {
			if (CommonUtil.isEmpty(entity)) {
				throw new Exception("delete：entity为空");
			}

			ID id = getPrimaryKey(entity);
			delete((Class<T>) entity.getClass(), id);
		} catch (Exception e) {
			flag = false;
			throw new Exception(e);
		}
		return flag;
	}

	/**
	 * 删除与此实体相同属性的对象
	 * 
	 * @param entity
	 * @throws BaseException
	 */
	public boolean deleteEqual(T entity) throws Exception {
		boolean flag = true;
		try {
			if (CommonUtil.isEmpty(tableName)) {
				throw new Exception("deleteEqual：tableName不能为空");
			}
			HashMap<String, Object> params = new HashMap<String, Object>();
			params.put("tableName", tableName);
			List<EqualObj> conditionList = this.getEqualList(entity);
			params.put("conditionList", conditionList);
			this.executeDelete("IbatisCommonDao_deleteEqual", params);
		} catch (Exception e) {
			flag = false;
			throw new Exception(e);
		}
		return flag;
	}

	/**
	 * 仅设置标志删除
	 * 
	 * @param entity
	 * @throws BaseException
	 */
	public boolean deleteByFlag(Class<T> entityClass, ID id)
			throws Exception {
		boolean flag = true;
		try {
			T entity = entityClass.newInstance();
			this.setPropertyValue(entity, primaryKeyName, id);
			this.setPropertyValue(entity, flagName, 1);
			this.update(entity);
		} catch (Exception e) {
			flag = false;
			throw new Exception(e);
		}
		return flag;
	}

	/**
	 * 自动判断增加或者修改
	 * 
	 * @param entity
	 * @throws BaseException
	 */
	public void saveOrUpdate(T entity) throws Exception {
		
		if (entity == null) {
			throw new Exception("saveOrUpdate：entity不能为空");
		}
		ID id = this.getPrimaryKey(entity);
		if (id == null) {
			this.insert(entity);
		} else {
			this.update(entity);
		}
		
	}

	/**
	 * 统计当前跟当前实体属性一致的记录数
	 * 
	 * @param entity
	 * @return
	 * @throws BaseException
	 */
	public Long countEqual(T entity) throws Exception {
	
		if (CommonUtil.isEmpty(tableName)) {
			throw new Exception("countEqual：tableName不能为空");
		}
		HashMap<String, Object> params = new HashMap<String, Object>();
		params.put("tableName", tableName);
		List<EqualObj> conditionList = getEqualList(entity);
		params.put("conditionList", conditionList);
		return this.queryForLong("IbatisCommonDao_countEqual", params);
		
	}

	/**
	 * 统计属性一致的记录数
	 * 
	 * @param entityClass
	 * @return
	 */
	public Long countByProperty(Class<T> entityClass, String propertyName,
			Object PropertyValue) throws Exception {
		T entity = entityClass.newInstance();
		this.setPropertyValue(entity, propertyName, PropertyValue);
		return this.countEqual(entity);
		
	}
	
	/**
	 * 执行自定义SQL查询语句
	 * @param sql
	 * @return map
	 */
	public List<Map<String, Object>> excuteQuerySql(String sql){
		
		List<Map<String, Object>> list = this.queryForMapObjectList(
				"IbatisCommonDao_excuteQuerySql", sql);
		return list;
	}
	
	/**
	 * 执行自定义SQL查询语句
	 * @throws InstantiationException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 */
	public List<T> excuteQuerySql(Class<T> entityClass,String sql) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
		List<Map<String, Object>> list = excuteQuerySql(sql);
		return this.getListInstanceFromListMap(entityClass, list);
	}
	
}